/***************************************************************************
 *   Copyright (C) 2009 by Zheng Yonglei
 *   zhengyonglei@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#include "TestWord.h"
#include "Logger.h"

TestWord::TestWord() :
	Word(),
	isActive(false),
	state(TS_New),
	isFrozen(false),
	successivePassCount(0),
	coolingTimeRemain(0),
	totalTestCount(0),
	lastTestInterval(0),
	testHistoryScore(0),
	complexity(0),
	passLastTest(false),
	mTestFinishThreshould(2)
{
}

TestWord::TestWord(int id) :
	Word(id),
	isActive(false),
	state(TS_New),
	isFrozen(false),
	successivePassCount(0),
	coolingTimeRemain(0),
	totalTestCount(0),
	lastTestInterval(0),
	testHistoryScore(0),
	complexity(0),
	passLastTest(false),
	mTestFinishThreshould(2)
{
}

TestWord::~TestWord()
{
}

void TestWord::testPassed()
{
	mTestRecords[OPT.getCurrendDate()].pass();
	passLastTest = true;
	updateTestProgress();
	updateTrainingData();
}
void TestWord::testFailed()
{
	mTestRecords[OPT.getCurrendDate()].fail();
	passLastTest = false;
	updateTestProgress();
	updateTrainingData();
}

void TestWord::setTestRecords(QString testRecordString)
{
	mTestRecords.clear();

	QStringList dateList = testRecordString.split("|", QString::SkipEmptyParts);
	if (dateList.isEmpty())
		return;

	for (int i=0; i<dateList.size(); i++)
	{
		if (!dateList[i].contains(":"))
		{
			LOG<<"Error. Illegal test_records format."<<endl;
			continue;
		}

		QString date = dateList[i].left(dateList[i].indexOf(":"));
		QString testResult =  dateList[i].right(dateList[i].size() - dateList[i].indexOf(":") -1);
		QDate testDate = QDate::fromString(date, DATE_FORMAT);
		mTestRecords.insert(make_pair(testDate, TestRecord(testDate, testResult)));
	}
}

QString TestWord::getTestRecordString()
{
	if (mTestRecords.empty())
		return QString("");
	else
	{
		QStringList recordList;
		map<QDate, TestRecord>::iterator record_it;
		for (record_it = mTestRecords.begin(); record_it != mTestRecords.end(); record_it++)
		{
			recordList<<record_it->second.getTestRecordString();
		}

		return recordList.join(TEST_RECORD_SEPARATOR);
	}
}

void TestWord::updateTestProgress()
{
	if (passLastTest)
		successivePassCount++;
	else
		successivePassCount--;

	if (successivePassCount > mTestFinishThreshould)
		successivePassCount = mTestFinishThreshould;

	if (successivePassCount < 0)
		successivePassCount = 0;

	if (successivePassCount == mTestFinishThreshould)
	{
		state = TS_Finished;
		LOG<<"This word is finished."<<endl;
	}
	else
	{
		state = TS_Testing;
		LOG<<"This word is NOT finished."<<endl;
	}
}

void TestWord::setFrozenRemainCycle(int factor)
{
	coolingTimeRemain = factor;

	if(coolingTimeRemain < 4)
		coolingTimeRemain = 4;

	LOG<<"coolingTimeRemain="<<coolingTimeRemain<<endl;
}

int TestWord::calculateTotalTestCount()
{
	if (mTestRecords.empty())
		return 0;

	int totalCount=0;
	for (map<QDate, TestRecord>::iterator it = mTestRecords.begin(); it != mTestRecords.end(); it++)
		totalCount += it->second.getTestCount();

	return totalCount;
}

int TestWord::calculateLastTestInterval()
{
	if (mTestRecords.size() > 0)
	{
		map<QDate, TestRecord>::iterator it = mTestRecords.end();
		while(it != mTestRecords.begin())
		{
			it--;
			if (it->first != OPT.getCurrendDate())
				break;
		}

		return it->second.getInterval();
	}
	else
		return 0;
}

int TestWord::calculateTestHistoryScore()
{
	vector<bool> pass;
	for (	map<QDate, TestRecord>::iterator record_it = mTestRecords.begin();
			record_it != mTestRecords.end();
			record_it++)
	{
		pass.push_back(record_it->second.passFirst());
	}

	int history_score_inc;
	int history_score = 0;
	if (pass.size() < 2)
		return 0;

	int i = pass.size()-1;
	int index = i;
	if (pass[i - 1])
		history_score_inc = 1;
	else
		history_score_inc = -1;

	while(index > 0)
	{
		index--;
		if (pass[index] == pass[i-1])
			history_score += history_score_inc;
		else
			break;
	}

	return history_score;
}

int TestWord::calculateComplexity()
{
	QList<QChar> letters;
	for (int i=0; i<word.size(); i++)
	{
		if (letters.contains(word[i]))
			continue;
		else
			letters<<word[i];
	}

	return letters.size();
}

void TestWord::updateTrainingData()
{
	totalTestCount = calculateTotalTestCount();
	lastTestInterval = calculateLastTestInterval();
	testHistoryScore = calculateTestHistoryScore();
	complexity = calculateComplexity();
}
